/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ejercicio.practica5;

import static java.lang.Thread.sleep;
import java.util.Random;

/**
 *
 * @author manolo
 */
class algEisenbergMcGuire implements Runnable {

    enum estados {

        REPOSO, ESPERA, ACTIVO
    };
    static volatile estados[] flags;
    private int id;
    static volatile int turno;
    volatile int indice;
    static int N = 3;

    public algEisenbergMcGuire(int id) {
        this.id = id;
    }

    private void ocupado() {
        Random rm = new Random();
        try {
            sleep(rm.nextInt(1500));
        } catch (InterruptedException ex) {
            System.out.println("Error: " + ex);
        }
    }

    private void SeccionNoCritica() {
        System.out.println("Proceso " + id + " está en la región no critica");
        ocupado();
    }

    private void SeccionCritica() {
        System.out.println("Proceso " + id + " entrando en la sección critica");
        ocupado();
        System.out.println("Proceso " + id + " saliendo de la sección critica");
    }

    private void algoritmoEisenberg() {
        while (true) {
            do {
                /* Solicitamos el recurso */
                flags[id] = estados.ESPERA;                
                indice = turno;
                
                /* Comprobar los procesos hasta encontrar todos los procesos en reposo */
                while (indice != id) {
                    if (flags[indice] != estados.REPOSO) {
                        indice = turno;
                    } else {
                        indice = (indice + 1) % N;
                    }
                }

                /* Se intenta adquirir el recurso */
                flags[id] = estados.ACTIVO;

                /* Se intenta encontrar si existe alguno activo */
                indice = 0;
                while ((indice < N) && ((indice == id) || (flags[indice] != estados.ACTIVO))) {
                    indice++;
                }
                /* Si no existen procesos activos y tenemos el turno procedemos. */
            } while (!((indice >= N) && ((turno == id) || (flags[turno] == estados.REPOSO))));

            turno = id;
            SeccionCritica();
            postEisenberg();
        }

    }

    private void postEisenberg() {
        indice = (turno + 1) % N;
        while (flags[indice] == estados.REPOSO) {
            indice = (indice + 1) % N;
        }
        turno = indice;
        flags[id] = estados.REPOSO;
    }

    @Override
    public void run() {
        SeccionNoCritica();
        algoritmoEisenberg();

    }

    public static void main(String[] args) throws InterruptedException {
        flags = new estados[N];
        for (int i = 0; i < N; i++) {
            flags[i] = estados.REPOSO;
        }
        turno =0;
        // Lanzamiento de los hilos/procesos
        Thread[] p = new Thread[N];
        for (int i = 0; i < N; i++) {
            p[i] = new Thread(new algEisenbergMcGuire(i));
            p[i].start();
        }
    }

}
